/**
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
package org.python.pydev.logging.ping;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.python.pydev.core.log.Log;
import com.aptana.shared_core.structure.Tuple;
/**
* This is a log ping that makes the pinging asynchronous.
*/
public class AsyncLogPing implements ILogPing {
public static final int SCHEDULE_TIME = 100;
private final SynchedLogPing internal;
private List<Object> operations = new ArrayList<Object>();
private Object lockOperations = new Object();
private Object lockExecuteCommands = new Object();
private Job job;
public AsyncLogPing(String location) {
this(location, new LogInfoProvider(), new LogPingSender());
}
public AsyncLogPing(String location, ILogPingProvider provider, ILogPingSender sender) {
this(new SynchedLogPing(location, provider, sender));
}
public AsyncLogPing(SynchedLogPing logPing) {
internal = logPing;
job = new Job("Consume commands") {
@Override
protected IStatus run(IProgressMonitor monitor) {
consumeAllCommands(true);
return Status.OK_STATUS;
}
};
job.setSystem(true);
job.setPriority(Job.BUILD);
}
/**
* Adds operation and schedules job to treat it later.
*/
public void addPingOpenEditor() {
String msg = internal.createPingOpenEditorEncodedMessage();
synchronized (lockOperations) {
operations.add(new Tuple<String, String>("addEncodedMessage", msg));
}
job.schedule(SCHEDULE_TIME);
}
public void addPingStartPlugin() {
String msg = internal.createPingStartPluginEncodedMessage();
synchronized (lockOperations) {
operations.add(new Tuple<String, String>("addEncodedMessage", msg));
}
job.schedule(SCHEDULE_TIME);
}
/**
* Adds operation and schedules job to treat it later.
*/
public void send() {
synchronized (lockOperations) {
operations.add("send");
}
job.schedule(SCHEDULE_TIME);
}
/**
* Yes, this is the exception that's not asynchronous! Note that sends won't execute at this time.
* So, commands will only be added at this time without any actual send.
*/
public void stop() {
consumeAllCommands(false);
internal.stop();
}
/**
* Actually executes the commands.
*
* If send is passed, send command are handled, otherwise they're ignored.
*/
private void consumeAllCommands(final boolean send) {
ArrayList<Object> local;
synchronized (lockOperations) {
local = new ArrayList<Object>(operations);
operations.clear();
}
synchronized (lockExecuteCommands) {
boolean containsSend = local.contains("send");
if (containsSend) {
for (Iterator<Object> it = local.iterator(); it.hasNext();) {
if ("send".equals(it.next())) {
it.remove(); //remove any send
}
}
}
//make all pings before a send.
for (Object cmd : local) {
if (cmd instanceof Tuple) {
Tuple tuple = (Tuple) cmd;
if ("addEncodedMessage".equals(tuple.o1)) {
internal.addEncodedMessage((String) tuple.o2);
continue;
}
}
//if it got here, the command wasn't handled.
Log.log("Invalid command: " + cmd);
}
if (send) {
//make the send.
if (containsSend) {
internal.send();
}
}
}
}
}